package com.hadoop.project.mvc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.hadoop.project.context.BaseContext;
import com.hadoop.project.entity.constant.Constant;
import com.hadoop.project.entity.constant.JwtClaimsConstant;
import com.hadoop.project.entity.dto.UserEditDTO;
import com.hadoop.project.entity.dto.UserLoginDTO;
import com.hadoop.project.entity.po.User;
import com.hadoop.project.entity.vo.UserLoginVO;
import com.hadoop.project.entity.exception.BusinessException;
import com.hadoop.project.mvc.mappers.UserMapper;
import com.hadoop.project.config.properties.JwtProperties;
import com.hadoop.project.mvc.service.UserService;
import com.hadoop.project.utils.GenCode;
import com.hadoop.project.utils.JwtUtil;
import com.hadoop.project.utils.QQEmailUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.hadoop.project.entity.constant.QQConstant.EmailContent;

@Service
@RequiredArgsConstructor //自动生成一个包含所有 final 字段的构造函数，类似于@Autowired
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final JwtProperties jwtProperties;
    // 存储验证码
    private final Map<String, String> emailVerificationCodes = new ConcurrentHashMap<>();

    /**
     * 用户登录
     *
     * @param userLoginDto
     * @return
     */
    @Override
    public UserLoginVO login(UserLoginDTO userLoginDto) {

        // 登录校验（判断用户是否存在）
        String userEmail = userLoginDto.getEmail();
        String password = userLoginDto.getPassword();
        String code = userLoginDto.getCode();
        // 根据邮箱查询用户信息
        User userInfo = userMapper.getByEmail(userEmail);
        // 情况1：邮箱加验证码登录
        if (userEmail != null && code != null && (password == null || password.isEmpty())) {
            // 判断用户是否存在,如果不存在，则创建新用户
            if (userInfo == null) {
                // 验证码校验
                codeVerification(userEmail, code);
                // 属性拷贝
                User user = BeanUtil.copyProperties(userLoginDto, User.class);
                userMapper.insertUser(user);
                user.setId(user.getId());
                // 生成jwt令牌
                UserLoginVO userLoginVO = generateJwt(user);
                return userLoginVO;
            }
            // 验证码校验
            codeVerification(userEmail, code);
            // 生成jwt令牌
            UserLoginVO userLoginVO = generateJwt(userInfo);
            return userLoginVO;
        }
        // 情况2：邮箱加密码登录
        if (userEmail != null && password != null && (code == null || code.isEmpty())) {
            // 判断用户是否存在
            if (userInfo == null) {
                throw new BusinessException(600, Constant.USER_NOT_EXIST);
            }
            // 判断密码是否正确
            //密码和用户名比对
            //对前端传递的明文密码进行MD5加密
            password = DigestUtils.md5DigestAsHex(password.getBytes());
            if (!password.equals(userInfo.getPassword())) {
                throw new BusinessException(600, Constant.PASSWORD_ERROR);
            }

            //权限验证成功，生成jwt令牌
            UserLoginVO UserLoginVO = generateJwt(userInfo);
            return UserLoginVO;
        }
        throw new BusinessException(600, Constant.LOGIN_TYPE_ERROR);
    }

    /**
     * 发送验证码
     *
     * @param email
     * @param num
     */
    @Override
    public void getVerificatioCode(String email, Integer num) {
        String code = GenCode.getCode(num);
        // 存储验证码，设置过期时间（例如5分钟）
        emailVerificationCodes.put(email, code);
        emailVerificationCodes.put(email + "_timestamp", String.valueOf(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)));

        try {
            QQEmailUtil.sendEmail(email, code, EmailContent);
        } catch (Exception e) {
            // 移除验证码及其过期时间
            emailVerificationCodes.remove(email);
            emailVerificationCodes.remove(email + "_timestamp");
            throw new RuntimeException("邮件发送失败，请稍后再试！", e);
        }
    }

    /**
     * 用户注册
     *
     * @param userLoginDto
     */
    @Override
    public void register(UserLoginDTO userLoginDto) {
        // 注册校验（判断用户是否存在）
        String userEmail = userLoginDto.getEmail();
        String password = userLoginDto.getPassword();
        // 对前端传递的明文密码进行MD5加密后再传入数据库
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        userLoginDto.setPassword(password);
        User userInfo = userMapper.getByEmail(userEmail);
        if (userInfo != null) {
            throw new BusinessException(601, Constant.USER_EXIST);
        }
        // 验证码校验
        codeVerification(userEmail, userLoginDto.getCode());
        // 属性拷贝
        User user = BeanUtil.copyProperties(userLoginDto, User.class);
        // 插入用户信息到数据库
        userMapper.insertUser(user);
    }

    /**
     * 修改密码
     *
     * @param userLoginDto
     */
    @Override
    public void modifyPassword(UserLoginDTO userLoginDto) {
        // 修改密码校验（判断用户是否存在）
        String userEmail = userLoginDto.getEmail();
        User userInfo = userMapper.getByEmail(userEmail);
        if (userInfo == null) {
            throw new BusinessException(600, Constant.USER_NOT_EXIST);
        }
        // 对前端传递的明文密码进行MD5加密后存入数据库
        String password = userLoginDto.getPassword();
        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
        userLoginDto.setPassword(md5Password);
        // 验证码校验
        codeVerification(userEmail, userLoginDto.getCode());
        // 属性拷贝
        User user = BeanUtil.copyProperties(userLoginDto, User.class);
        // 修改密码
        userMapper.updataPassword(user);
    }

    /**
     * 添加密码或修改用户名
     *
     * @param userEditDto
     */
    @Override
    public void editInfo(UserEditDTO userEditDto) {
        // 获取当前登录用户id
        Long id = BaseContext.getCurrentId();
        String password = userEditDto.getPassword();
        if (password != null && !password.isEmpty()){
            String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
            userEditDto.setPassword(md5Password);
        }
        userEditDto.setId(id);
        User user = BeanUtil.copyProperties(userEditDto, User.class);
        userMapper.updateInfo(user);
    }

    /**
     * 验证码校验通用方法
     *
     * @param email,code
     */
    protected void codeVerification(String email, String code) {

        // 检查验证码是否存在
        String storedCode = emailVerificationCodes.get(email);
        String storedTimestamp = emailVerificationCodes.get(email + "_timestamp");

        if (storedCode == null || storedTimestamp == null) {
            throw new BusinessException(600, Constant.CODE_STATUS_ERROR);
        }

        // 检查验证码是否过期
        long currentTime = System.currentTimeMillis();
        long expirationTime = Long.parseLong(storedTimestamp);
        if (currentTime > expirationTime) {
            emailVerificationCodes.remove(email);
            emailVerificationCodes.remove(email + "_timestamp");
            throw new BusinessException(600, Constant.CODE_INVALID);
        }

        // 检查验证码是否正确
        if (!storedCode.equals(code)) {
            throw new BusinessException(600, Constant.CODE_ERROR);
        }
    }

    /**
     * 生成jwt令牌专用方法
     *
     * @param userInfo
     * @return
     */
    protected UserLoginVO generateJwt(User userInfo) {
        //权限验证成功，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();

        claims.put(JwtClaimsConstant.USER_ID, userInfo.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getUserSecretKey(),
                jwtProperties.getUserTtl(),
                claims);

        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(userInfo.getId())
                .userName(userInfo.getUserName())
                .token(token)
                .build();
        return userLoginVO;
    }
}
